//
// Created by jinbang.li on 2023/6/23.
//

#include "OpShader.h"
#include "../Log/OpLog.h"
#include <GLES2/gl2.h>

#define GET_STR(x) #x
static const char *vertexShader = GET_STR(
        attribute vec4 aPosition;
        attribute vec2 aTexCoord;
        varying vec2 vTexCoord;
        void main(){
            vTexCoord = vec2(aTexCoord.x,1.0 - aTexCoord.y);
            gl_Position = aPosition;
        }
);
static const char *fragYUV420P = GET_STR(
        precision mediump float ;
        varying vec2 vTexCoord;
        uniform sampler2D yTexture;
        uniform sampler2D uTexture;
        uniform sampler2D vTexture;
        void main(){
            vec3 yuv;
            vec3 rgb;
            yuv.r = texture2D(yTexture,vTexCoord).r;
            yuv.g = texture2D(uTexture,vTexCoord).r - 0.5;
            yuv.b = texture2D(vTexture,vTexCoord).r - 0.5;
            rgb = mat3(1.0,     1.0,    1.0,
                       0.0,-0.39465,2.03211,
                       1.13983,-0.58060,0.0)*yuv;
            //输出像素颜色
            gl_FragColor = vec4(rgb,1.0);
        }
);
static GLuint InitShader(const char  *code,GLint type){
    GLuint sh = glCreateShader(type);
    if(sh == 0)
    {
        OPLOGE("glCreateShader %d failed!",type);
        return 0;
    }

    glShaderSource(sh,
                   1,
                   &code,
                   0);

    glCompileShader(sh);

    //获取编译情况
    GLint status;
    glGetShaderiv(sh,GL_COMPILE_STATUS,&status);
    if(status == 0)
    {
        OPLOGE("glCompileShader failed!");
        return 0;
    }

    return sh;
}
/**
 * 初始化着色器
 * @return
 */
 bool OpShader::Init() {
     vsh = InitShader(vertexShader,GL_VERTEX_SHADER);
     if(vsh == 0)
     {
         OPLOGE("InitShader GL_VERTEX_SHADER failed!");
         return false;
     }


     //片元yuv420 shader初始化
     fsh = InitShader(fragYUV420P,GL_FRAGMENT_SHADER);
     if(fsh == 0)
     {
         OPLOGE("InitShader GL_FRAGMENT_SHADER failed!");
         return false;
     }



     /////////////////////////////////////////////////////////////
     //创建渲染程序
     program = glCreateProgram();
     if(program == 0)
     {
         OPLOGE("glCreateProgram failed!");
         return false;
     }
     //渲染程序中加入着色器代码
     glAttachShader(program,vsh);
     glAttachShader(program,fsh);

     //链接程序
     glLinkProgram(program);
     GLint status = 0;
     glGetProgramiv(program,GL_LINK_STATUS,&status);
     if(status != GL_TRUE)
     {
         OPLOGE("glLinkProgram failed!");
         return false;
     }
     glUseProgram(program);



    ///OpenGL 坐标系
     static float vers[] = {
             1.0f,-1.0f,0.0f,//右下
             -1.0f,-1.0f,0.0f,//左下
             1.0f,1.0f,0.0f,//右上
             -1.0f,1.0f,0.0f,//左上
     };
     GLuint apos = (GLuint)glGetAttribLocation(program,"aPosition");
     glEnableVertexAttribArray(apos);
     //传递顶点
     glVertexAttribPointer(apos,3,GL_FLOAT,GL_FALSE,12,vers);

     //纹理坐标系 材质数据
     static float txts[] = {
             1.0f,0.0f , //右下
             0.0f,0.0f,//左下
             1.0f,1.0f,//右上
             0.0,1.0//左上
     };
     GLuint atex = (GLuint)glGetAttribLocation(program,"aTexCoord");
     glEnableVertexAttribArray(atex);
     glVertexAttribPointer(atex,2,GL_FLOAT,GL_FALSE,8,txts);


     //材质纹理初始化
     //设置纹理层
     glUniform1i( glGetUniformLocation(program,"yTexture"),0); //对于纹理第1层
     glUniform1i( glGetUniformLocation(program,"uTexture"),1); //对于纹理第2层
     glUniform1i( glGetUniformLocation(program,"vTexture"),2); //对于纹理第3层
     return true;
}

void OpShader::Draw() {
    if (!program)return;
    glDrawArrays(GL_TRIANGLE_STRIP,0,4);
 }
 void OpShader::GetTexture(unsigned int index, int width, int height, unsigned char *buf) {
     if (texts[index] == 0){
         glGenTextures(1,&texts[index]);
         glBindTexture(GL_TEXTURE_2D,texts[index]);
         glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
         glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
         glTexImage2D(GL_TEXTURE_2D,0,GL_LUMINANCE,width,height,0,GL_LUMINANCE,GL_UNSIGNED_BYTE,NULL);
     }
     glActiveTexture(GL_TEXTURE0 + index);
     glBindTexture(GL_TEXTURE_2D,texts[index]);
     glTexSubImage2D(GL_TEXTURE_2D,0,0,0,width,height,GL_LUMINANCE,GL_UNSIGNED_BYTE,buf);
 }